#include <rtdevice.h>
#include <board.h>

/* STM32F103 ADC implementation */
#ifdef BSP_USING_ADC1

static struct rt_adc_device stm32_adc;
static ADC_HandleTypeDef hadc1;

static rt_uint32_t stm32_adc_get_channel(rt_uint8_t channel)
{
    /* Convert logical channel to physical ADC channel */
    static const rt_uint32_t channels[] = {
        ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2, ADC_CHANNEL_3,
        ADC_CHANNEL_4, ADC_CHANNEL_5, ADC_CHANNEL_6, ADC_CHANNEL_7
    };
    
    if (channel < sizeof(channels)/sizeof(channels[0])) {
        return channels[channel];
    }
    
    return ADC_CHANNEL_0;
}

static rt_err_t stm32_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
{
    ADC_ChannelConfTypeDef config = {0};
    
    if (enabled) {
        config.Channel = stm32_adc_get_channel(channel);
        config.Rank = 1;
        config.SamplingTime = ADC_SAMPLETIME_55CYCLES;
        
        if (HAL_ADC_ConfigChannel(&hadc1, &config) != HAL_OK) {
            return RT_ERROR;
        }
    }
    
    return RT_OK;
}

static rt_err_t stm32_adc_convert(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
{
    ADC_ChannelConfTypeDef config = {0};
    
    config.Channel = stm32_adc_get_channel(channel);
    config.Rank = 1;
    config.SamplingTime = ADC_SAMPLETIME_55CYCLES;
    
    if (HAL_ADC_ConfigChannel(&hadc1, &config) != HAL_OK) {
        return RT_ERROR;
    }
    
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 10);
    *value = HAL_ADC_GetValue(&hadc1);
    HAL_ADC_Stop(&hadc1);
    
    return RT_OK;
}

static const struct rt_adc_ops stm32_adc_ops = {
    .enabled = stm32_adc_enabled,
    .convert = stm32_adc_convert,
};

int stm32_adc_init(void)
{
    /* ADC1 configuration */
    hadc1.Instance = ADC1;
    hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    hadc1.Init.ContinuousConvMode = DISABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion = 1;
    
    if (HAL_ADC_Init(&hadc1) != HAL_OK) {
        return RT_ERROR;
    }
    
    /* Register ADC device */
    stm32_adc.ops = &stm32_adc_ops;
    rt_hw_adc_register(&stm32_adc, "adc1", RT_DEVICE_FLAG_RDWR, &hadc1);
    
    return RT_OK;
}
INIT_BOARD_EXPORT(stm32_adc_init);

#endif /* BSP_USING_ADC1 */